﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Windows.Forms;

namespace ClassFolio.Model
{
    /// <summary>
    /// Класс предназначен для сохранения пользовательских настроек различных частей программы
	/// </summary>
	/// <remarks>
	/// Класс не создается явно, для получения экземпляра класса необходимо воспользоваться статическим 
    /// методом Current()
	/// </remarks>
    [Serializable]
    public class Adjustment : ISerializable
    {
	
	#region Cтатические методы для работы с классом
		
		public static Adjustment Default
        {
			get
			{
				return _adjustment;
			}
        }
        public static void Save()
        { 
            IFormatter formatter = new BinaryFormatter();

		
			using (Stream stream = new FileStream(AdjustmentFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
				formatter.Serialize(stream, Adjustment.Default);
            }
        }
        public static void Reload()
        {
			if (!Directory.Exists(Path.GetDirectoryName(AdjustmentFile)))
				Directory.CreateDirectory(Path.GetDirectoryName(AdjustmentFile));

			using (Stream stream = new FileStream(AdjustmentFile, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read))
            {
                IFormatter formatter = new BinaryFormatter();
				try
				{
					_adjustment = (Adjustment)formatter.Deserialize(stream);
				}
				catch 
				{
					_adjustment = new Adjustment();
				}
				
            }
		}
		public static string AppDir = Path.GetDirectoryName(Application.ExecutablePath);
		public static string AdjustmentFile;
		public static int DefaultCount = 10;

	#endregion

	#region Properties

		/// <summary>
		/// Количество записей отображаемых в запросах из таблице Users
		/// </summary>
		/// <remarks>Количество записей не может быть более 50 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
		public int CountRecordActors 
		{
			get { return this._countRecordActors; }
			set
			{
				if (value > 50)
					this._countRecordActors = 50;
				else if (value < 1)
					this._countRecordActors = 1;
				else
					this._countRecordActors = value;
			}
		}

		/// <summary>
		/// Количество записей отображаемых в запросах из таблицы Role
		/// </summary>
		/// <remarks>Количество записей не может быть более 50 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
		public int CountRecordRole
		{
			get { return this._countRecordRole; }
			set
			{
				if (value > 50)
					this._countRecordRole = 50;
				else if (value < 1)
					this._countRecordRole = 1;
				else
					this._countRecordRole = value;
			}
		}

		/// <summary>
		/// Количество записей отображаемых в запросах из таблицы Departments
		/// </summary>
		/// <remarks>Количество записей не может быть более 50 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
		public int CountRecordDept
		{
			get { return this._countRecordDept; }
			set
			{
				if (value > 50)
					this._countRecordDept = 50;
				else if (value < 1)
					this._countRecordDept = 1;
				else
					this._countRecordDept = value;
			}
		}

		/// <summary>
		/// Количество записей отображаемых в списках доступа
		/// </summary>
		/// <remarks>Количество записей не может быть более 20 и менее 1. 
		/// Ограничение отслеживается автоматически, при попытке присвоить значение не находящееся в указанном интервале, сохраняется 
		/// минимально возможное значение, если диапазаон выходит за рамки нижней границы и максимально возможное, если значение 
		/// выходит за границы верхнего диапазона</remarks>
		public int CountRowComboBox
		{
			get { return this._countRowComboBox; }
			set
			{
				if (value > 20)
					this._countRowComboBox = 20;
				else if (value < 1)
					this._countRowComboBox = 1;
				else
					this._countRowComboBox = value;
			}
		}

		#region Списки
		
		public ComboBoxItemList UserList { get { return this._userList; } }
        public ComboBoxItemList ServerList { get { return this._serverList; } }

		#endregion

		#region Фильтры
		
		public FiltersList UserFilters { get { return this._userFilters; } }

		#endregion
	
	#endregion

	#region Сериализация

		protected Adjustment(SerializationInfo info, StreamingContext context)
        {
            this.CountRecordActors = info.GetInt32("CountRecordActors");
			this.CountRecordRole = info.GetInt32("CountRecordRole");
			this.CountRecordDept = info.GetInt32("CountRecordDept");
			this.CountRowComboBox = info.GetInt32("CountRowComboBox");
			this._userList = (ComboBoxItemList)info.GetValue("UserList", _userList.GetType());
            this._serverList = (ComboBoxItemList)info.GetValue("ServerList", _userList.GetType());
			this._userFilters = (FiltersList)info.GetValue("UserFilters", _userFilters.GetType());
        }
        
		[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("CountRecordActors", this.CountRecordActors);
			info.AddValue("CountRecordRole", this._countRecordRole);
			info.AddValue("CountRecordDept", this._countRecordDept);
			info.AddValue("CountRowComboBox", this._countRowComboBox);
			info.AddValue("UserList", this._userList);
			info.AddValue("UserFilters", this._userFilters);
            info.AddValue("ServerList", this._serverList);
		}

		#endregion

	#region Private

		// Значения
		private int _countRecordActors = 1;
		private int _countRecordRole = 1;
		private int _countRecordDept = 1;
		private int _countRowComboBox = 1;
		
		// Списки
		private ComboBoxItemList _userList = new ComboBoxItemList();
        private ComboBoxItemList _serverList = new ComboBoxItemList();

		// Фильтры
		private FiltersList _userFilters = new FiltersList();

		private static Adjustment _adjustment;
		private Adjustment() { }

		#endregion 
	}

	#region Классы для сериализации элементов списка

	[Serializable]
	public class ComboBoxItemList
	{
        public ComboBoxItemList Add(ComboBoxItem cbItem)
		{ 
			ComboBoxItem cb = _cbList.Where(i => i.ID == cbItem.ID && i.Name == cbItem.Name && i.FullName == cbItem.FullName).
				ElementAtOrDefault(0);
			if (cb != null)
				cb.Weight++;
			else
			{
				int countRow = Adjustment.Default == null ? Tools.DefaultRowCount : Adjustment.Default.CountRowComboBox;
				if (countRow <= _cbList.Count)
					_cbList.Remove(_cbList.Where(i => i.Weight == _cbList.Min(ii => ii.Weight)).ElementAtOrDefault(0));
				_cbList.Add(cbItem);
			}
            return this;
		}
		public void Clear()
		{
			_cbList.Clear();
		}
		public ComboBoxItem Selected { get; set; }

        public List<ComboBoxItem> Items { get { return this._cbList; } set { this._cbList = value; } }

		//Private
		private List<ComboBoxItem> _cbList = new List<ComboBoxItem>();
	}

	[Serializable]
	public class ComboBoxItem
	{
		//Constructors
		public ComboBoxItem(int id) { this._id = id; }
		public ComboBoxItem(string shortName) { this._shortName = shortName; }
		public ComboBoxItem(int id, string shortName) { this._id = id; this._shortName = shortName; }
		public ComboBoxItem(int id, string shortName, string fullName) : this(id, shortName) { this._fullName = fullName; }
	
		//Properties
		public int ID { get { return this._id; } }
		public string Name { get { return this._shortName; } }
		public string FullName { get { return this._fullName; } }
		public int Weight { get; set; }

		//Private
		private int _id;
		private string _shortName;
		private string _fullName;
	}

	#endregion

	#region Сериализация фильтров

	[Serializable]
	public class FiltersList
	{
		public void Add(FilterItem filterItem)
		{
			_filterList.Add(filterItem);
		}
		public void Clear()
		{
			_filterList.Clear();
		}
		public FilterItem this[string name] 
		{
			get { return this._filterList.Where(i => i.Name == name).ElementAtOrDefault(0); }
		}
		public List<FilterItem> Items { get { return this._filterList; } }

		//Private
		private List<FilterItem> _filterList = new List<FilterItem>();
	}

	[Serializable]
	public class FilterItem
	{
		public FilterItem(string name, SqlSwitch swth, List<string> captions)
		{
			this.Name = name;
			this.Condition = swth.Condition.Select(x => x).ToList();
			this.SqlCaptions = captions.Select(x => x).ToList();
		}

		//Properties
		public string Name { get; set; }
		public List<string> SqlCaptions { get; set; }
		public List<SqlCase> Condition { get; set; }

	}

	#endregion
}
